package com.kk.transactional.controller;

import com.kk.transactional.entity.Order;
import com.kk.transactional.entity.Person;
import com.kk.transactional.service.impl.OrderServiceImpl;
import com.kk.transactional.service.impl.PersonServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * <p>
 *  声明式事务
 * </p>
 *
 * @author little_lunatic
 * @since 2025-06-05
 */
@Controller
@RequestMapping("/demo2")
@Api("demo-control-transaction")
public class TransactionTemplateController {

    @Autowired
    private OrderServiceImpl orderService;

    @Autowired
    private PersonServiceImpl personService;

    @Autowired
    private PlatformTransactionManager transactionManager;

    /**
     * 全部成功或全部失败
     */
    @ApiOperation("REQUIRED")
    @PostMapping("REQUIRED")
    public void demo1() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_REQUIRED_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_REQUIRED_INNER");
                personService.save(person);
                // 内层事务提交
                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }
            throw new RuntimeException();  //外层事务回滚，影响内层
//            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }

    /**
     * 全部成功或全部失败
     */
    @ApiOperation("REQUIRED2")
    @PostMapping("REQUIRED2")
    public void demo2() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_REQUIRED2_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_REQUIRED2_INNER");
                personService.save(person);

            throw new RuntimeException();  //内层事务回滚，影响外层
//                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }
            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }



    @ApiOperation("REQUIRES_NEW")
    @PostMapping("REQUIRES_NEW")
    public void demo4() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_REQUIREDNEW_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_REQUIREDNEW_INNER");
                personService.save(person);
                // 内层事务提交
                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }
            throw new RuntimeException("OUT ROLLBACK"); //外层事务回滚
//            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }

    @ApiOperation("REQUIRES_NEW2")
    @PostMapping("REQUIRES_NEW2")
    public void demo5() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_REQUIREDNEW2_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_REQUIREDNEW2_INNER");
                personService.save(person);
                throw new RuntimeException("INNER"); //内层事务回滚
                // 内层事务提交
//                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }

            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }


    /**
     * 存在事务嵌套运行，不存在就新建
     *
     * 内层回滚不影响外层，外层回滚影响内层
     */
    @ApiOperation("NESTED")
    @PostMapping("NESTED")
    public void demo7() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_NESTED_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_NESTED_INNER");
                personService.save(person);
                // 内层事务提交
                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }
            throw new RuntimeException(); // 外层事务回滚
//            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }
    @ApiOperation("NESTED2")
    @PostMapping("NESTED2")
    public void demo8() {
        DefaultTransactionDefinition dtd1 = new DefaultTransactionDefinition();
        dtd1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        dtd1.setTimeout(3);

        // 开启外层事务
        TransactionStatus transaction1 = transactionManager.getTransaction(dtd1);
        try {
            // 外层事务
            Order order = new Order();
            order.setGoods("PROPAGATION_NESTED2_OUT");
            orderService.save(order);

            DefaultTransactionDefinition dtd2 = new DefaultTransactionDefinition();
            dtd2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
            dtd2.setTimeout(3);
            // 开启内层事务
            TransactionStatus transaction2 = transactionManager.getTransaction(dtd2);
            try {
                // 内层事务
                Person person = new Person();
                person.setName("PROPAGATION_NESTED2_INNER");
                personService.save(person);
                throw new RuntimeException(); //内层事务回滚
                // 内层事务提交
//                transactionManager.commit(transaction2);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(transaction2);
            }
            transactionManager.commit(transaction1);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transaction1);
        }
    }
}
